---------------Jumblezzz---------------
A 4am crack                  2017-11-19
---------------------------------------

Name: Jumblezzz
Genre: educational
Year: 1987
Publisher: Mindplay, Inc.
Platform: Apple ][+ or later
Media: single-sided 5.25-inch floppy
OS: DOS 3.3
Previous cracks: none

                   ~

               Chapter 0
 In Which Various Automated Tools Fail
          In Interesting Ways


COPYA
  read error on third pass

Locksmith Fast Disk Backup
  unable to read track $15
  copy boots DOS, shows a title screen,
  then hangs with the drive motor on

EDD 4 bit copy (no sync, no count)
  no errors, but copy boots DOS, shows
  a title screen, then displays
  "DISK ERROR 35W" and hangs

Copy ][+ nibble editor
  track $15 is almost entirely sync
  bytes, with the occasional $D5 nibble
  (almost certainly a protection track)

Disk Fixer
  entire disk is standard except T15
  T00,S00 -> DOS 3.3 bootloader
  T01,S09 -> startup program is "HELLO"
  standard DOS 3.3 disk catalog on T11

Why didn't any of my copies work?
  specially formatted nibble sequence
  on track $15, designed to fool even
  the best bit copiers

Next steps:

  1. Find the protection check that is
     reading track $15
  2. Disable it
  3. Declare victory (*)

(*) go to the gym

                   ~

               Chapter 1
         In Which We Get Lucky


One thing that all protection checks
have in common is they need to access
the disk drive. Since most protection
checks exploit edge cases of how bits
are stored on disk, they need to use
the lowest level access methods to
manipulate those bits manually.

The lowest level way to "read" a disk
is the data latch softswitch address in
the $C0xx range. For slot 6, it's
$C0EC, but to allow disks to boot from
any slot, developers usually use code
like this:

  LDX <slot number x 16>
  LDA $C08C,X

There's nothing that says you have to
use the X-register as the index or the
accumulator as the load register. But
most disks do, out of convention I
suppose (or fear of messing up such
low-level code in subtle ways).

Also, since developers don't actually
want people finding their protection-
related code, they may try to encrypt
it or obfuscate it on disk, in memory,
or both. But eventually, the code must
exist and the code must run, and it
must run on my machine, and I have the
final say on what my machine does or
does not do.

But sometimes you get lucky.

Turning to my trusty Disk Fixer sector
editor, I search the non-working copy
for "BD 8C C0", which is the opcode
sequence for "LDA $C08C,X".

[Disk Fixer]
  ["F"ind]
    ["H"ex]
      ["BD 8C C0"]

                 --v--

------------- DISK SEARCH -------------

$00/$02-$75   $00/$02-$8B   $00/$02-$B4
$00/$02-$E1   $00/$02-$EB   $00/$02-$F6
$00/$03-$2F   $00/$03-$39   $00/$03-$4F
$00/$03-$59   $00/$03-$64   $00/$03-$71
$00/$03-$79   $00/$03-$8B   $00/$03-$95
$00/$06-$A4   $00/$06-$C0   $00/$07-$27
$00/$07-$37   $00/$07-$3C   $17/$0A-$52
$17/$0A-$62   $17/$0A-$7D   $17/$0A-$8E
$17/$0A-$98   $17/$0A-$A7

                 --^--

The matches on track $00 are part of
DOS 3.3, i.e. not suspicious. But the
cluster of matches on track $17 are
highly suspect.

                   ~

               Chapter 2
      In Which We Find Ourselves
          In Enemy Territory


The protection routine appears to start
at offset $1D.

                 --v--

T17,S0A
----------- DISASSEMBLY MODE ----------
; get boot slot (x16)
001D:A6 2B          LDX   $2B

; save zero page addresses on stack
001F:A5 FD          LDA   $FD
0021:48             PHA
0022:A5 FE          LDA   $FE
0024:48             PHA

; get RWTS parameter table address
0025:20 E3 03       JSR   $03E3
0028:84 FD          STY   $FD
002A:85 FE          STA   $FE

; track $15 -- the mystery track!
002C:A0 04          LDY   #$04
002E:A9 15          LDA   #$15
0030:91 FD          STA   ($FD),Y

; RWTS command = seek
0032:A0 0C          LDY   #$0C
0034:A9 00          LDA   #$00
0036:91 FD          STA   ($FD),Y

; slow down IIgs (has no effect on
; other machines)
0038:AD 36 C0       LDA   $C036
003B:29 7F          AND   #$7F
003D:8D 36 C0       STA   $C036

; disable last line of RWTS that turns
; off the drive motor
0040:A9 60          LDA   #$60
0042:8D 4D BE       STA   $BE4D

; call the RWTS to execute the seek to
; track $15
0045:20 E3 03       JSR   $03E3
0048:20 D9 03       JSR   $03D9

; restore the RWTS code (but the drive
; motor is still on)
004B:A9 BD          LDA   #$BD
004D:8D 4D BE       STA   $BE4D

; if the seek failed for some reason,
; exit
0050:B0 65          BCS   $00B7

; find $D5 nibble
0052:BD 8C C0       LDA   $C08C,X
0055:10 FB          BPL   $0052
0057:48             PHA
0058:68             PLA
0059:C9 D5          CMP   #$D5
005B:D0 F5          BNE   $0052

; initialize a checksum
005D:A0 00          LDY   #$00
005F:8C E6 91       STY   $91E6

; count number of $F7 nibbles before
; another $D5 nibble
0062:BD 8C C0       LDA   $C08C,X
0065:10 FB          BPL   $0062
0067:C9 D5          CMP   #$D5
0069:F0 0F          BEQ   $007A
006B:C9 F7          CMP   #$F7
006D:D0 01          BNE   $0070
006F:C8             INY

; the sum of the nibbles themselves
; constitutes the checksum
0070:18             CLC
0071:6D E6 91       ADC   $91E6
0074:8D E6 91       STA   $91E6
0077:4C 5E 91       JMP   $915E
007A:98             TYA
007B:F0 E0          BEQ   $005D

; skip $FF nibbles
007D:BD 8C C0       LDA   $C08C,X
0080:10 FB          BPL   $007D
0082:48             PHA
0083:68             PLA
0084:C9 FF          CMP   #$FF
0086:F0 F5          BEQ   $007D

; if next nibble is $D5, fail
0088:C9 D5          CMP   #$D5
008A:F0 35          BEQ   $00C1

; skip several more nibbles
008C:A0 05          LDY   #$05
008E:BD 8C C0       LDA   $C08C,X
0091:10 FB          BPL   $008E
0093:48             PHA
0094:68             PLA
0095:88             DEY
0096:D0 F6          BNE   $008E

; skip $FF nibbles
0098:BD 8C C0       LDA   $C08C,X
009B:10 FB          BPL   $0098
009D:48             PHA
009E:68             PLA
009F:C9 FF          CMP   #$FF
00A1:F0 F5          BEQ   $0098

; if next nibble is not $D5, fail
00A3:C9 D5          CMP   #$D5
00A5:D0 1A          BNE   $00C1

; skip $FF nibbles
00A7:BD 8C C0       LDA   $C08C,X
00AA:10 FB          BPL   $00A7
00AC:C9 FF          CMP   #$FF
00AE:D0 11          BNE   $00C1

; verify checksum, branch on failure
00B0:AD E6 91       LDA   $91E6
00B3:C9 10          CMP   #$10
00B5:D0 0A          BNE   $00C1

; success path falls through to here --
; turn off drive motor and continue
; elsewhere
00B7:BD 88 C0       LDA   $C088,X

; restore zero page
00BA:68             PLA
00BB:85 FE          STA   $FE
00BD:68             PLA
00BE:85 FD          STA   $FD

; return to caller gracefully
00C0:60             RTS

; all failures lead here --
; wipe memory
00C1:A2 80          LDX   #$80
00C3:A9 A0          LDA   #$A0
00C5:99 FF 08       STA   $08FF,Y
00C8:C8             INY
00C9:D0 FA          BNE   $00C5
00CB:EE C3 91       INC   $91C3
00CE:CA             DEX
00CF:D0 F4          BNE   $00C5
00D1:AD 8A C0       LDA   $C08A

; display encrypted error message
; "DISK ERROR 35W"
00D4:20 2F FB       JSR   $FB2F
00D7:20 58 FC       JSR   $FC58
00DA:A0 0E          LDY   #$0E
00DC:B9 E7 91       LDA   $91E7,Y
00DF:49 BB          EOR   #$BB
00E1:99 B4 05       STA   $05B4,Y
00E4:88             DEY
00E5:10 F5          BPL   $00DC
00E7:78             SEI

; hang forever
00E8:30 FE          BMI   $00E8

(This is the behavior I saw on my non-
working EDD bit copy.)

There are no side effects. Replacing
the first byte with an "RTS" will
bypass the entire thing.

T17,S0A,$1D: A6 -> 60

]PR#6
...works...

Quod erat liberandum.

---------------------------------------
A 4am crack                    No. 1528
------------------EOF------------------
